﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Xna.Framework;

namespace Example5_Collisions.Model
{
    class Model
    {

        const float m_rightEdge = 1;

        private Level m_level = new Level();
        private Player m_player = new Player();

        bool m_hasCollidedWithGround = false;

        internal void Update(float a_elapsedTime)
        {
            //Get the old position
            Vector2 oldPos = m_player.GetPosition();

            //Get the new position
            m_player.Update(a_elapsedTime);

            Vector2 newPos = m_player.GetPosition();

            //Collide
            m_hasCollidedWithGround = false;
            Vector2 speed = m_player.GetSpeed();
            Vector2 afterCollidedPos = Collide(oldPos, newPos, m_player.m_sizes, ref speed, out m_hasCollidedWithGround);

            //set the new speed and position after collision
            m_player.SetPosition(afterCollidedPos.X, afterCollidedPos.Y);
            m_player.SetSpeed(speed.X, speed.Y);

        }

        //simple collision response functionality
        private Vector2 Collide(Vector2 a_oldPos, Vector2 a_newPos, Vector2 a_size, ref Vector2 a_velocity, out bool a_outCollideGround)
        {
            a_outCollideGround = false;
            //Can we move to the position safely?
            if (m_level.IsCollidingAt(a_newPos, a_size))
            {
                //if not try only the X movement, indicates that a collision with ground or roof has occured
                Vector2 xMove = new Vector2(a_newPos.X, a_oldPos.Y);

                if (m_level.IsCollidingAt(xMove, a_size) == false)
                {

                    //did we collide with ground?
                    if (a_velocity.Y > 0)
                    {
                        a_outCollideGround = true;
                    }

                    a_velocity.Y *= 0; //reverse the y velocity and some speed lost in the collision
                    a_velocity.X *= 0.50f;// friction should be time-dependant


                    return xMove;
                }
                else
                {
                    //try Y movement, indicates that a collision with wall has occured
                    Vector2 yMove = new Vector2(a_oldPos.X, a_newPos.Y);
                    if (m_level.IsCollidingAt(yMove, a_size) == false)
                    {
                        a_velocity.X = 0;
                        return yMove;
                    }
                }
                //remain at the same position
                return a_oldPos;
            }

            return a_newPos;
        }

        internal bool CanJump()
        {
            return m_hasCollidedWithGround;
        }

        internal void DoJump()
        {
            if (CanJump())
            {
                m_player.DoJump();
            }
        }


        internal Level GetLevel()
        {
            return m_level;
        }

        internal Microsoft.Xna.Framework.Vector2 GetPlayerPosition()
        {
            return m_player.GetPosition();
        }

        internal float GetPlayerSpeed()
        {
            return m_player.GetSpeed().Length();
        }

        internal void MoveLeft()
        {
            m_player.SetSpeed(-5, m_player.GetSpeed().Y);
        }

        internal void MoveRight()
        {
            m_player.SetSpeed(5, m_player.GetSpeed().Y);
        }
    }
}
